<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>我的技术与生活——分享基于H5实现扫码功能 | Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <link rel="shortcut icon" href="../../../../imgs/shortcut-icon.ico" type="image/x-icon">
  <link rel="stylesheet" href="../../../../css/public.css" />
  <link rel="stylesheet" href="../../../../css/layout.css" />
  <link rel="stylesheet" href="../../../../css/iconfont.css" />
  <link rel="stylesheet" href="../../../../css/APlayer.min.css" />
  <script src="../../../../js/APlayer.min.js"></script>
  <script src="../../../../js/jquery.min.js"></script>
  <script src="../../../../js/jquery.pjax.min.js"></script>

  <script src='//unpkg.com/valine/dist/Valine.min.js'></script>
  <script>
    document.title = `我的技术与生活——分享基于H5实现扫码功能`
  </script>
<meta name="generator" content="Hexo 6.0.0"></head>

<style>
  .load {
    width: 100%;
    height: 100vh;
    background-color: rgb(37, 35, 40);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: relative;
    z-index: 9999;
  }
  .load-circle {
    width: 80px;
    height: 80px;
    border: 8px solid orange;
    border-bottom-color: transparent;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    animation: rotate 1s linear infinite;
    filter: drop-shadow(0 0 3px orange);
  }
  .load-circle-inner {
    width: 40px;
    height: 40px;
    border: 8px solid orange;
    border-top-color: transparent;
    border-radius: 50%;
    animation: rotate-reverse .5s linear infinite;
  }
  .load-text {
    margin-top: 20px;
    font-size: 24px;
    color: orange;
    display: flex;
  }
  .load-text span {
    margin: 0 5px;
    text-shadow: 5px 5px 5px orange;
    animation: move 1s linear infinite;
  }
  .load-text span:nth-child(1) {
    animation-delay: -0.6s;
  }
  .load-text span:nth-child(2) {
    animation-delay: -0.5s;
  }
  .load-text span:nth-child(3) {
    animation-delay: -0.4s;
  }
  .load-text span:nth-child(4) {
    animation-delay: -0.3s;
  }
  .load-text span:nth-child(5) {
    animation-delay: -0.2s;
  }
  .load-text span:nth-child(6) {
    animation-delay: -0.1s;
  }
  @keyframes rotate {
    0% { transform: rotate(0); }
    100% { transform: rotate(360deg); }
  }
  @keyframes rotate-reverse {
    0% { transform: rotate(0); }
    100% { transform: rotate(-360deg); }
  }
  @keyframes move {
    0% { transform: translateY(0%) rotate(0) scale(1); }
    20% { transform: translateY(20%) rotate(10deg) scale(1.2); }
    80% { transform: translateY(-10%) rotate(-20deg) scale(.8);}
    100% { transform: translateY(0) rotate(0) scale(1); }
  }

  .progress {
    position: fixed;
    left: 0; top: 0;
    width: 0;
    height: 3px;
    background-color: green;
    transition: all cubic-bezier(0.215, 0.610, 0.355, 1) .1s;
    z-index: 9999;
  }

  .to-up {
    animation: toUp .5s 1;
  }
  .gray {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100vh;
    z-index: 9999;
    display: none;
    pointer-events: none;
    background-color: #000;
    mix-blend-mode: color;
  }
  @keyframes toUp {
    from { transform: translateY(15px); opacity: 0; }
    to { transform: translateY(0) ; opacity: 1; }
  }
</style>
<body>
  <div id="load" class="load">
    <div class="load-circle">
      <div class="load-circle-inner"></div>
    </div>
    <p class="load-text">
      <span>L</span>
      <span>O</span>
      <span>A</span>
      <span>D</span>
      <span>I</span>
      <span>N</span>
      <span>G</span>
    </p>
  </div>
  <div id="container" class="container w-100 vh-100" style="display: none;">
    <header class="header">
  <div class="header-wrapper">
    <div class="header-left">
      <div class="header-search">
        <input id="search-input" type="text" class="header-search--input" placeholder="请输入要检索的文章标题" />
        <span id="search-btn" class="header-search--icon"><i class="iconfont icon-sousuo"></i></span>
      </div>
      <div id="search-layer" class="header-search--layer hidden">
        <p class="title">
          <span>以下是搜索内容：</span>
          <span id="close-layer-btn">关闭</span>
        </p>
        <ul>
        </ul>
      </div>
    </div>
    <div class="header-right">
      <ul class="header-menu">
        <li>
          <a href="https://aizener.github.io/">
            <i class="header-menu--icon iconfont icon-shouye"></i>
            <span class="header-menu--span">首页</span>
          </a>
        </li>
        <li>
          <a href="https://aizener.github.io/log">
            <i class="header-menu--icon iconfont icon-rizhi"></i>
            <span class="header-menu--span">日志</span>
          </a>
        </li>
        <li>
          <a href="https://aizener.github.io/link">
            <i class="header-menu--icon iconfont icon-youqinglianjie"></i>
            <span class="header-menu--span">友情链接</span>
          </a>
        </li>
        <li>
          <a href="https://aizener.github.io/about">
            <i class="header-menu--icon iconfont icon-guanyuwomen"></i>
            <span class="header-menu--span">关于我</span>
          </a>
        </li>
      </ul>
    </div>
  </div>
</header>

<script>
  const ipt = document.querySelector('#search-input')
  const btn = document.querySelector('#search-btn')
  const layer = document.querySelector('#search-layer')
  const posts = JSON.parse(`[{"title":"关于H5新特性拖放API讲解","path":"2022/03/24/关于H5新特性拖放API讲解/"},{"title":"分享基于H5实现扫码功能","cover":"https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9c64349191a94bf19bcaeb14a62d328c~tplv-k3u1fbpfcp-zoom-crop-mark:3024:3024:3024:1702.awebp?","path":"2022/08/14/分享基于H5实现扫码功能/"},{"title":"在Vue项目中使用ESLint来检查代码","cover":"https://s3.bmp.ovh/imgs/2022/04/01/647275ce2adecce7.png","path":"2022/03/02/在Vue项目中使用ESLint来检查代码/"},{"title":"如何使用hexo-theme-cola主题","path":"2022/02/17/如何使用hexo-theme-cola主题/"},{"title":"基于Vue对主题修改的思考与实现","cover":"https://s3.bmp.ovh/imgs/2022/04/01/7d831a8e4b739ac2.png","path":"2022/04/01/基于Vue对主题修改的思考与实现/"},{"title":"趣味NodeJS之笔趣阁的小蜘蛛","cover":"https://s3.bmp.ovh/imgs/2022/04/01/05822287376d328d.png","path":"2022/03/08/趣味NodeJS之笔趣阁的小蜘蛛/"}]`)
  ipt.addEventListener('keyup', e => {
    if (e.key === 'Enter') {
      handleSearch()
    }
  })
  btn.addEventListener('click', () => {
    handleSearch()
  })

  document.querySelector('#close-layer-btn').addEventListener('click', () => {
    layer.classList.toggle('hidden')
  })

  function handleSearch() {
    if (ipt.value.trim() === '') {
      return
    }
    let html = ''
    const targetPosts = posts.filter(post => post.title.includes(ipt.value))
    targetPosts.forEach(post => {
      html += `
        <li>
          <div>
            <a href="/${post.path}">${post.title.replace(new RegExp(ipt.value), `<span>${ipt.value}</span>`)}</a>
          </div>
          <img src="${post.cover || '/imgs/default-cover.webp' }" />
        </li>
      `
    })
    if (html.trim () === '') {
      html += '<p class="empty">没有搜索到内容</p>'
    }
    layer.querySelector('ul').innerHTML = html
    layer.classList.remove('hidden')
  }
</script> 
    <section id="main" class="main">
      <div class="main-left-wrapper">
<div class="main-left">
  <div class="main-left--block">
    <div class="main-left--info">
      <img src="../../../../imgs/avatar.jpg"" class="main-left--avatar" />
      <div class="main-left--intro">
        <p class="main-left--name">Cola.</p>
        <div class="main-left--tags">
          <span class="main-left--tag">中二</span>
          <span class="main-left--tag">宅</span>
        </div>
      </div>
    </div>
  
    <div>
      <div class="main-left--motto">
        <p>“花有重开日，人无再少年”</p>
        <p>“一个简单普通的男孩”</p>
      </div>
      <div class="main-left--github">
        <span class="line"></span>
        <a target="_blank" rel="noopener" href="https://github.com/Aizener"><i class="logo iconfont icon-github-fill"></i></a>
        <span class="line"></span>
      </div>
      <div class="main-left--statics">
        <a href="/categories">
          <div>
            <span>2</span>
            <span>分类</span>
          </div>
        </a>
        <a href="/tags">
          <div>
            <span>7</span>
            <span>标签</span>
          </div>
        </a>
        <a href="/archives">
          <div>
            <span>4 </span>
            <span>归档</span>
          </div>
        </a>
      </div>
    </div>
  </div>

  <div class="main-left--block">
    <ul class="main-left--menu">
      
        <li>
          <a href="/">
            <span class="header-menu--span">小站首页</span>
            <i class="header-menu--icon iconfont icon-shouye"></i>
          </a>
        </li>
      
        <li>
          <a href="/log">
            <span class="header-menu--span">个人日志</span>
            <i class="header-menu--icon iconfont icon-rizhi"></i>
          </a>
        </li>
      
        <li>
          <a href="/link">
            <span class="header-menu--span">友情链接</span>
            <i class="header-menu--icon iconfont icon-youqinglianjie"></i>
          </a>
        </li>
      
        <li>
          <a href="/about">
            <span class="header-menu--span">关于自己</span>
            <i class="header-menu--icon iconfont icon-guanyuwomen"></i>
          </a>
        </li>
      
        <li>
          <a href="/tools">
            <span class="header-menu--span">我的工具</span>
            <i class="header-menu--icon iconfont icon-gongju"></i>
          </a>
        </li>
      
    </ul>
  </div>

  <div class="main-left--block">
    <div class="main-left--site">
      <h5 class="main-left--title">
        <span>站点信息</span>
        <i class="iconfont icon-zhandian"></i>
      </h5>
      <p class="main-left--subtitle">
        <span>文章数目：</span>
        <span>6 篇</span>
      </p>
      <p class="main-left--subtitle">
        <span>最近动态：</span>
        <span>6月前</span>
      </p>
      <p class="main-left--subtitle">
        <span>上线时间：</span>
        <span>410天</span>
      </p>
      <p class="main-left--subtitle">
        <span>当前版本：</span>
        <span>v1.0.2</span>
      </p>
    </div>
  </div>
</div></div>
      <div id="main-container" class="main-container">


  <style>
pre::-webkit-scrollbar {
  width: 5px;
  height: 10px;
  background-color:#F5F5F5;
}
/*定义滚动条轨道
内阴影+圆角*/
pre::-webkit-scrollbar-track {
  background-color:#F5F5F5;
}
/*定义滑块
内阴影+圆角*/
pre::-webkit-scrollbar-thumb {
  background-color: rgb(69, 83, 100);
}

pre:active {
  background-color: rgb(81, 95, 116);
}
</style>

<div class="article-container">
  <div class="article">
    <h1 class="article-title">分享基于H5实现扫码功能</h1>
    <div class="article-info">
      <div class="article-info--item">
        <div class="article-info--info">
          
          <div class="article-info--categories">
            <span>分类：</span>
            <a class="category-link" href="../../../../categories/Web%E5%89%8D%E7%AB%AF/">Web前端</a>
          </div>
          
          
          <div class="article-info--tags">
            <span>标签：</span>
            <a class="tag-link" href="../../../../tags/HTML5/" rel="tag">HTML5</a>
          </div>
          
          <p class="article-info--date">日期：2022-08-14 22:33:34</p>
        </div>
        <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9c64349191a94bf19bcaeb14a62d328c~tplv-k3u1fbpfcp-zoom-crop-mark:3024:3024:3024:1702.awebp?" alt="" class="article-cover">
      </div>
    </div>
    <article class="article-content">
      <blockquote>
<p>分享仅仅只是通过使用第三方库来实现基于H5页面的扫码功能，而不会去从<code>navigator.mediaDevices.getUserMedia</code>这个新的<code>Api</code>来一步步开发。</p>
</blockquote>
<p>如果对实现<code>H5</code>的扫码实现感兴趣的话，可以去看看：<a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia">navigator.mediaDevices.getUserMedia</a> 相关的MDN文档。</p>
<h2 id="功能介绍"><a href="#功能介绍" class="headerlink" title="功能介绍"></a>功能介绍</h2><p>先来说说<code>H5</code>的扫码常用两种使用场景，这里列举两种比较长哟的：<br>一种就是直接打开浏览器来进行扫码，这种就需要基于<code>H5</code>的原生功能来实现；<br>而另一种的话就是通过微信内置浏览器打开<code>H5</code>页面来进行调用微信的<code>SDK</code>实现扫码（当然也可以用<code>H5</code>原生功能实现）。</p>
<h2 id="基于H5来实现扫码"><a href="#基于H5来实现扫码" class="headerlink" title="基于H5来实现扫码"></a>基于H5来实现扫码</h2><p>这里我们需要使用别人封装好的一个<code>H5</code>扫码库：<a target="_blank" rel="noopener" href="https://github.com/mebjas/html5-qrcode">html5-qrcode</a>，这个库分为两种使用方式：</p>
<ul>
<li><code>Html5QrcodeScanner</code>： 默认带有UI到扫描功能，使用非常简单；</li>
<li><code>Html5Qrcode</code>：更灵活的扫描功能，没有默认的UI界面，自定义性更强。</li>
</ul>
<blockquote>
<p><strong>注意</strong><br>因为扫码需要调起手机摄像头功能，而这是一个比较隐私的功能，所以需要部署的网站是<code>https</code>协议的或者使用本地<code>localhost</code>也可以，<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia">MDN文档说明</a>。</p>
</blockquote>
<p>这是官网<code>Html5QrcodeScanner</code>实现的二维码扫描样例：  </p>
<p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a56bd5465067488389e672b596657dbd~tplv-k3u1fbpfcp-watermark.image" alt="pixel4_barcode_480.gif"></p>
<p>可以看到，这样的UI并不适合于我们开发使用（除非你或者老板觉得很Nice！），所以我们就得需要使用<code>Html5Qrcode</code>的方式来实现二维码扫描功能了。</p>
<p>使用<code>Html5Qrcode</code>来实现二维码扫描也非常的简单，通过官网的代码例子即可实现，代码如下：</p>
<pre class="line-numbers language-js" data-language="js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">&#123;</span> Html5Qrcode <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">"html5-qrcode"</span>

<span class="token keyword">const</span> html5QrCode <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Html5Qrcode</span><span class="token punctuation">(</span><span class="token string">"reader"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token function-variable function">qrCodeSuccessCallback</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">decodedText<span class="token punctuation">,</span> decodedResult</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">&#123;</span> <span class="token literal-property property">fps</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token literal-property property">qrbox</span><span class="token operator">:</span> <span class="token punctuation">&#123;</span> <span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token number">250</span><span class="token punctuation">,</span> <span class="token literal-property property">height</span><span class="token operator">:</span> <span class="token number">250</span> <span class="token punctuation">&#125;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">;</span>

html5QrCode<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span> <span class="token literal-property property">facingMode</span><span class="token operator">:</span> <span class="token string">"environment"</span> <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> config<span class="token punctuation">,</span> qrCodeSuccessCallback<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> err<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<ol>
<li><p>通过给<code>Html5Qrcode</code>传入一个<code>ID</code>选择器来创建对应<code>DOM</code>节点的对象，然后通过<code>start</code>方法即可打开手机的摄像头来实现扫码功能（会弹出授权框）。</p>
</li>
<li><p>其中，<code>facingMode</code>表示开启的是前置摄像后还是后置摄像后，其中<code>environment</code>表示打开后置摄像后即对着环境扫描，而<code>user</code>表示打开前置摄像头，即照自己。</p>
</li>
<li><p>当扫描成功后，会执行<code>qrCodeSucccessCallback</code>的回调方法，参数有两个：<code>decodedText</code>和<code>decodedResult</code>；其中<code>decodedText</code>是二维码扫描的结果值，<code>decodeResult</code>则是一个扫描成功后返回的对象并包含前者。</p>
</li>
</ol>
<h2 id="基于微信SDK来扫描"><a href="#基于微信SDK来扫描" class="headerlink" title="基于微信SDK来扫描"></a>基于微信SDK来扫描</h2><p>当通过微信的内置浏览器打开H5页面时，此时是可以通过微信SDK来调用微信的二维码扫描功能的，这种方式相比于原生H5体验会更加的好。</p>
<h3 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h3><p>使用微信SDK的话，需要服务端来配合，首先看服务端怎么使用：</p>
<ol>
<li><p>首先在 <code>设置与开发-&gt;公众号设置-&gt;功能设置-&gt;JS接口安全域名</code> 中下载的指定文件并填写对应的服务器目录里面，再填写对应的域名即可配置成功；</p>
</li>
<li><p>通过<a target="_blank" rel="noopener" href="https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62">签名算法</a>来生成对应的签名，一定要好好阅读不然很容易出错；</p>
</li>
<li><p>把生成的签名通过接口返回。</p>
</li>
</ol>
<h3 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h3><p>当服务端完成配置后，客户端需要下载对应的<a target="_blank" rel="noopener" href="https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#3">JSSDK</a>，引入完成后，通过一下代码即可初始化配置：</p>
<pre class="line-numbers language-js" data-language="js"><code class="language-js">wx<span class="token punctuation">.</span><span class="token function">ready</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    wx<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
      <span class="token literal-property property">debug</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来，若要查看传入的参数，可以在 pc 端打开，参数信息会通过 log 打出，仅在 pc 端时才会打印。</span>
      <span class="token literal-property property">appId</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token comment">// 必填，公众号的唯一标识</span>
      <span class="token literal-property property">timestamp</span><span class="token operator">:</span> <span class="token punctuation">,</span> <span class="token comment">// 必填，生成签名的时间戳</span>
      <span class="token literal-property property">nonceStr</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span> <span class="token comment">// 必填，生成签名的随机串</span>
      <span class="token literal-property property">signature</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">// 必填，签名</span>
      <span class="token literal-property property">jsApiList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">// 必填，需要使用的 JS 接口列表</span>
    <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>上面的参数，除了<code>timestamp</code>和<code>nonceStr</code>还有<code>signature</code>字段都是通过服务端返回的，完成以上步骤后，通过调用对应<code>API</code>即可实现二维码扫描功能：</p>
<pre class="line-numbers language-js" data-language="js"><code class="language-js">wx<span class="token punctuation">.</span><span class="token function">scanQRCode</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
  <span class="token literal-property property">needResult</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token comment">// 默认为0，扫描结果由微信处理，1则直接返回扫描结果，</span>
  <span class="token literal-property property">scanType</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"qrCode"</span><span class="token punctuation">,</span><span class="token string">"barCode"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// 可以指定扫二维码还是一维码，默认二者都有</span>
  <span class="token function-variable function">success</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">var</span> result <span class="token operator">=</span> res<span class="token punctuation">.</span>resultStr<span class="token punctuation">;</span> <span class="token comment">// 当needResult 为 1 时，扫码返回的结果</span>
  <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>效果图如下：</p>
<p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6a85ac6cae634847a862b4145f6e6a2d~tplv-k3u1fbpfcp-watermark.image" alt="demo11.gif"></p>
<p>以上，就是通过<code>H5</code>实现二维码功能的小分享了，并没有去研究原生的<code>API</code>来实现，而是使用的第三方库，这样对于业务开发来更加快速一点，而想了解实现原理的可以去了解。</p>
<p>至此，分享就到此结束啦:)</p>

    </article>
    
    <div class="read-nums">
      <!-- id 将作为查询条件 -->
      <span id="2022/08/14/分享基于H5实现扫码功能/" class="leancloud_visitors" data-flag-title="Your Article Title">
        <em class="post-meta-item-text">浏览量</em>
        <i class="leancloud-visitors-count"></i>
      </span>
    </div>
    <div class="comments-intro">
      <h2>评论区</h2>
      <p>欢迎你留下宝贵的意见，昵称输入QQ号会显示QQ头像哦~</p>
    </div>
    <div id="vcomments" class="vcomments"></div>
    
  </div>
  <div class="article-catelogue">
    <div class="article-catelogue--wrapper">
      <div class="catelogue catelogue-1">
        <h3>目录</h3>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.</span> <span class="toc-text">功能介绍</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9F%BA%E4%BA%8EH5%E6%9D%A5%E5%AE%9E%E7%8E%B0%E6%89%AB%E7%A0%81"><span class="toc-number">2.</span> <span class="toc-text">基于H5来实现扫码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9F%BA%E4%BA%8E%E5%BE%AE%E4%BF%A1SDK%E6%9D%A5%E6%89%AB%E6%8F%8F"><span class="toc-number">3.</span> <span class="toc-text">基于微信SDK来扫描</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%8D%E5%8A%A1%E7%AB%AF"><span class="toc-number">3.1.</span> <span class="toc-text">服务端</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%A2%E6%88%B7%E7%AB%AF"><span class="toc-number">3.2.</span> <span class="toc-text">客户端</span></a></li></ol></li></ol>
      </div>
      
        <div class="catelogue catelogue-2">
           
          
            <p>
              <span>下一篇</span>
              <a href="/2022/04/01/基于Vue对主题修改的思考与实现/">基于Vue对主题修改的思考与实现</a>
            </p>
          
        </div>
      
    </div>
  </div>
</div>

<script src="http://cdn.yangxiang.cc/prism.js"></script>

<script>
  // var定义，避免pjax重新进来造成的重复声明错误
  var config = JSON.parse('{"enable":true,"appId":"Pf8zCXGEH1qsprnWfikVVujL-gzGzoHsz","appKey":"qOqoiUHhH1TGtLRUYURkLRQX","placeholder":"请留下你宝贵的意见吧~","meta":["nick"],"recordIP":true,"visitor":true,"enableQQ":true}')
  new Valine({
    el: '#vcomments',
    appId: config.appId,
    appKey: config.appKey,
    placeholder: config.placeholder,
    meta: config.meta,
    recordIP: config.recordIP,
    visitor: config.visitor,
    enableQQ: config.enableQQ,
    path: '2022/08/14/分享基于H5实现扫码功能/'
  })
</script>


<script>
  $(document).on('pjax:complete', function() {
    const tocs = document.querySelector('.toc')
    const links = tocs ? tocs.querySelectorAll('a') : []
    links.forEach(link => {
      link.addEventListener('click', e => {
        const href = decodeURIComponent(a.href)
        href.search(/#(.*)/)
        const id = RegExp.$1
        const target = document.querySelector('#' + id)
        const top = target.offsetTop
        document.documentElement.scrollTo({
          top: top - 100,
          behavior: 'smooth'
        })
        e.preventDefault()
      })
    })
  })
</script> 

</div>
      <div class="main-right-wrapper"><div class="main-right">
  <div class="main-right--board">
    <div class="main-right--title">
      <h5>公告栏</h5>
      <i class="iconfont icon-gonggao"></i>
    </div>
    <div class="main-right--content">
      Hello~大噶好。唔系可乐爱宅着，欢迎你们来到我的博客小站，希望能在这里收获到有用的东西哦！ 
    </div>
  </div>

  <div id="aplayer" class="main-right--music"></div>

  <div class="operate-items">
    <div class="operate-item backtop">
      <i class="iconfont icon-huidaodingbu"></i>
      <span>回到顶部</span>
    </div>
    
    <div class="operate-item turn-comment hidden">
      <i class="iconfont icon-pinglun"></i>
      <span>查看评论</span>
    </div>
    
  </div>

  <div class="main-right--site">
    <div class="main-right--power">
      <p>Power By <a target="_blank" rel="noopener" href="https://hexo.io/zh-cn/docs/">Hexo</a>.</p>
      <p>Theme：<a target="_blank" rel="noopener" href="https://github.com/Aizener/hexo-theme-cola">Cola.</a></p>
    </div>
    <p class="main-right--refer"><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn/#/Integrated/index">蜀ICP备2022005384号-1</a> </p>
  </div>
</div>

<script>
  function setOperateItem () {
    const reg = /\d{4}\/\d{2}\/\d{2}\/.+/
    const path = location.pathname
    const commentDom = document.querySelector('.turn-comment')
    if (commentDom) {
      if (reg.test(path) || path.match(/\/log\/.+/)) {
        commentDom.classList.remove('hidden')
      } else {
        commentDom.classList.add('hidden')
      }
    }
  }

  setOperateItem()
  const musics = JSON.parse(`[{"name":"安河桥","artist":"宋冬野","url":"http://ting6.yymp3.net:82/new25/songdongye/11.mp3","cover":"https://img2.baidu.com/it/u=1260056724,1076343118&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"},{"name":"卡布达","artist":"暂无","url":"music/kabuda.mp3","cover":"https://img2.baidu.com/it/u=705831265,2862720033&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"}]`)
  const ap = new APlayer({
    container: document.querySelector('#aplayer'),
    audio: musics,
  })

  $(document).on('pjax:complete', function() {
    setOperateItem()
  })

  document.querySelector('.backtop').addEventListener('click', () => {
    document.documentElement.scrollTo({
      top: 0,
      behavior: 'smooth'
    })
  })
  const dom = document.querySelector('.turn-comment')
  dom && dom.addEventListener('click', () => {
    const commentDom = document.querySelector('.comments-intro')
    if (!commentDom) return
    const top = commentDom.offsetTop, height = commentDom.offsetHeight
    document.documentElement.scrollTo({
      top: top - 2 * height,
      behavior: 'smooth'
    })
  })
</script></div>
    </section>
  </div>
  <div id="progress" class="progress"></div>
  <div id="gray" class="gray"></div>

  <script>
    function initScroll () {
      document.addEventListener('scroll', () => {
        const doc = document.documentElement
        const scrollTop = doc.scrollTop
        const pageHeight = doc.offsetHeight
        const clientHeight = doc.clientHeight
        const ratio = scrollTop / (pageHeight - clientHeight)
        const progress = document.querySelector('#progress')
        const avatarImg = document.querySelector('.main-left--avatar')
        progress.style.width = (100 * ratio) + '%'
        avatarImg.style.transform = `rotate(${360 * ratio}deg)`
      })
    }

    const rootPath = "/"

    const checkAndSetArticlePageLayout = () => {
      if (/^\/?\d{4}\/\d{2}\/\d{2}\/.*/.test(location.pathname.replace(rootPath, ''))) {
        $('.main-container, .main-right, .main-right-wrapper').addClass('is-article')
      } else {
        $('.main-container, .main-right, .main-right-wrapper').removeClass('is-article')
      }
    }

    const gray = "none"
    const setGrayStyle = () => {
      if (gray === 'none') {
        return
      } else if (gray === 'index') {
        location.pathname === '/' ? $('#gray').show() : $('#gray').hide()
      } else if (gray === 'all') {
        $('#gray').show()
      }
    }
    setGrayStyle()


    window.onload = function () {
      checkAndSetArticlePageLayout()
      setTimeout(() => {
        $('#load').slideUp()
        $('#container').slideToggle()
        setTimeout(() => {
          initScroll()
        }, 500)
      }, 500)
    }
    
    let status = 0
    // 对所有链接跳转事件绑定pjax容器container
    $(document).pjax('a[target!=_blank]', '#main-container', {
      container: '#main-container',
      fragment: '#main-container',
      timeout: 8000
    })

    $(document).on('pjax:start', function() {
    })
    $(document).on('pjax:complete', function() {
      status = 0
      $('.main-container').addClass('to-up').on('animationend', function() {
        $(this).removeClass('to-up')
      })
      setGrayStyle()
      checkAndSetArticlePageLayout()
    })
    $(document).on('pjax:popstate', function() {
      status = -1
      checkAndSetArticlePageLayout()
      // $('.main-container').fadeIn()
    })
  </script>
</body>
</html>